//
//  OrenNayar.hpp
//  RayTracer
//
//  Created by 俞云康 on 4/6/16.
//  Copyright © 2016 yushroom. All rights reserved.
//

#ifndef OrenNayar_hpp
#define OrenNayar_hpp

#include "BxDF.hpp"

class OrenNayar : public BxDF {
private:
    Color R;
    float A, B;
    
public:
    OrenNayar(const HitInfo* hit, const Color& reflectance, float sig)
    : BxDF(hit, BxDFType(BxDF_REFLECTION | BxDF_DIFFUSE)), R(reflectance) {
        float sigma = radians(sig);
        float sigma2 = sigma*sigma;
        A = 1.f - (sigma2 / (2.0f * (sigma2 + 0.33f)));
        B = 0.45f * sigma2 / (sigma2 + 0.09f);
    }
    
    virtual Color f(const Direction& wo, const Direction& wi) const override {
        float sin_theta_i = SinTheta(wi);
        float sin_theta_o = SinTheta(wo);
        
        //Compute cosine term of Oren-Nayar model
        float max_cos = 0.f;
        if (sin_theta_i > EPS && sin_theta_o > EPS) {
            float sin_phi_i = SinPhi(wi);
            float cos_phi_i = CosPhi(wi);
            float sin_phi_o = SinPhi(wo);
            float cos_phi_o = CosPhi(wo);
            float d_cos = cos_phi_i * cos_phi_o + sin_phi_i * sin_phi_o;
            max_cos = std::max(0.f, d_cos);
        }
        
        //Compute sine and tangent terms of Oren-Nayar model
        float sinalpha, tanbeta;
        if (AbsCosTheta(wi) > AbsCosTheta(wo)) {
            sinalpha = sin_theta_o;
            tanbeta = sin_theta_i / AbsCosTheta(wi);
        }
        else {
            sinalpha = sin_theta_i;
            tanbeta = sin_theta_o / AbsCosTheta(wo);
        }
        
        return R * INV_PI * (A + B * max_cos * sinalpha * tanbeta);
    }
};

#endif /* OrenNayar_hpp */
